#pragma once
#include "Event.hpp"

namespace Typhoon {
		template<class Owner, class T> class Property {
			public:
				Property(Owner owner);
				~Property();

				void operator = (Property<Owner, T> &other);

				T Get();
				T operator () (void);
				T operator = (const T& other);

				operator const T ();
				
				const T& GetValue();

				void Set(T value);
				Event<Owner> Changed;

				

				struct EventData {
					Owner owner;
					T Current;
					T Old;
				};

				Event<EventData> ChangedWithOld;
				
			    T operator + (T value);
				T operator - (T value);
				T operator * (T value);
				T operator / (T value);
				T operator += (T value);
				T operator -= (T value);
				T operator *= (T value);
				T operator /= (T value);

			private:
				T value;
				Owner owner;
				
		};
	}

template<class Owner, class T> Typhoon::Property<Owner, T>::Property(Owner owner) {
	this->owner = owner;
}

template<class Owner, class T> void Typhoon::Property<Owner, T>::operator = (Property<Owner, T> &other) {
	Set( other.Get() );
}

template<class Owner, class T> Typhoon::Property<Owner, T>::~Property() {
}

template<class Owner, class T> void Typhoon::Property<Owner, T>::Set(T value) {
	if (this->value!=value) {
		if (ChangedWithOld.Count()>0) {
			EventData e;
			e.owner = owner;
			e.Current = value;
			e.Old = this->value;
			this->value = value;
			Changed(owner);
			ChangedWithOld(e);
		} else {
			this->value = value;
			Changed(owner);
		}
	}
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::Get() {
	return value;
}

template<class Owner, class T> const T& Typhoon::Property<Owner, T>::GetValue() {
	return value;
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator () () {
	return Get();
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator = (const T& other) {
	Set(other);
	return Get();
}

template<class Owner, class T> Typhoon::Property<Owner, T>::operator const T () {
	return Get();
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator + (T value) {
	return this->value + value;
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator - (T value) {
	return this->value - value;
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator * (T value) {
	return this->value * value;
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator / (T value) {
	return this->value / value;
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator += (T value) {
	Set(this->value + value);
	return Get();
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator -= (T value) {
	Set(this->value - value);
	return Get();
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator *= (T value) {
	Set(this->value * value);
	return Get();
}

template<class Owner, class T> T Typhoon::Property<Owner, T>::operator /= (T value) {
	Set(this->value / value);
	return Get();
}
